home *** CD-ROM | disk | FTP | other *** search
- /* Packet tracing - top level and generic routines, including hex/ascii
- * Copyright 1991 Phil Karn, KA9Q
- *
- * Mods by G1EMM
- *
- * Tracing to session taken from WNOS3, by Johan. K. Reinalda, WG7J
- */
- #include <stdio.h>
- #include <ctype.h>
- #include <time.h>
- #include "global.h"
- #include "config.h"
- #ifdef ANSIPROTO
- #include <stdarg.h>
- #endif
- #include "mbuf.h"
- #include "iface.h"
- #include "pktdrvr.h"
- #include "commands.h"
- #include "session.h"
- #include "trace.h"
-
- #ifdef TRACE
- static void ascii_dump __ARGS((FILE *fp,struct mbuf **bpp));
- static void ctohex __ARGS((char *buf,int16 c));
- static void fmtline __ARGS((FILE *fp,int16 addr,char *buf,int16 len));
- static void hex_dump __ARGS((FILE *fp,struct mbuf **bpp));
- static void showtrace __ARGS((struct iface *ifp));
- static void plain_dump __ARGS((FILE *fp,register struct mbuf **bpp));
- extern struct session *Current;
- extern struct session *Command;
- #ifdef MULTITASK
- extern int Nokeys;
- #endif
-
- #ifdef TNOS_68K
- #define fprintf traceprintf
- #endif
-
- extern int Tracesession;
- extern struct session *Trace;
-
- #ifdef MONITOR
- int Trace_compact_header = 0;
- static char *kissname __ARGS((struct iface *ifp,struct mbuf *bp,int type));
-
- #include "slip.h"
-
- static char *
- kissname(ifp, bp, type)
- struct iface *ifp;
- struct mbuf *bp;
- int type;
- {
- int port;
-
- if (ifp->type != CL_AX25 || type != CL_KISS)
- return ifp->name;
- port = (bp->data[0] & 0xF0) >> 4;
- if (Slip[ifp->xdev].kiss[port] == NULLIF)
- return ifp->name;
- return Slip[ifp->xdev].kiss[port]->name;
- }
-
- #endif
-
- int
- dostrace(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- if(Trace == NULLSESSION) {
- if (argc > 1)
- tputs ("Session tracing not available!\x07\n");
- argc = 0; /* No session setup, so don't allow turning it on ! */
- }
- return setbool(&Tracesession,"Trace to session",argc,argv);
- }
-
- /* Redefined here so that programs calling dump in the library won't pull
- * in the rest of the package
- */
-
- static char nospace[] = "No space!!\n";
-
- struct tracecmd Tracecmd[] = {
- "input", IF_TRACE_IN, IF_TRACE_IN,
- "-input", 0, IF_TRACE_IN,
- "output", IF_TRACE_OUT, IF_TRACE_OUT,
- "-output", 0, IF_TRACE_OUT,
- "broadcast", 0, IF_TRACE_NOBC,
- "-broadcast", IF_TRACE_NOBC, IF_TRACE_NOBC,
- "raw", IF_TRACE_RAW, IF_TRACE_RAW,
- "-raw", 0, IF_TRACE_RAW,
- "ascii", IF_TRACE_ASCII, IF_TRACE_ASCII|IF_TRACE_HEX,
- "-ascii", 0, IF_TRACE_ASCII|IF_TRACE_HEX,
- "hex", IF_TRACE_HEX, IF_TRACE_ASCII|IF_TRACE_HEX,
- "-hex", IF_TRACE_ASCII, IF_TRACE_ASCII|IF_TRACE_HEX,
- #ifdef MONITOR
- /* borrow a meaningless combination for the new trace type */
- #define IF_TRACE_PLAIN (IF_TRACE_ASCII|IF_TRACE_HEX)
- "monitor", IF_TRACE_PLAIN, IF_TRACE_ASCII|IF_TRACE_HEX,
- "-monitor", IF_TRACE_ASCII, IF_TRACE_ASCII|IF_TRACE_HEX,
- #endif
- "off", 0, 0xffff,
- NULLCHAR, 0, 0
- };
-
- void
- dump(ifp,direction,type,bp)
- register struct iface *ifp;
- int direction;
- unsigned type;
- struct mbuf *bp;
- {
- struct mbuf *tbp;
- void (*func) __ARGS((FILE *,struct mbuf **,int));
- int16 size;
- time_t timer;
- char *cp;
-
- if(ifp == NULL || (ifp->trace & direction) == 0)
- return; /* Nothing to trace */
-
- if(Tracesession) {
- /* Disable trace if this is not Trace-sessions,
- * or when shelled out, and not tracing to file */
- #ifdef MULTITASK
- if((Current != Trace || Nokeys) && (ifp->trfp == stdout))
- #else
- if((Current != Trace) && (ifp->trfp == stdout))
- #endif /* MULTITASK */
- return; /* Nothing to trace */
- } else {
- /* Disable trace on non-command sessions or when shelled out */
- #ifdef MULTITASK
- if((Current != Command || Nokeys) && (ifp->trfp == stdout))
- #else
- if((Current != Command) && (ifp->trfp == stdout))
- #endif
- return; /* Nothing to trace */
- }
-
- time(&timer);
- cp = ctime(&timer);
- cp[24] = '\0';
-
- switch(direction){
- case IF_TRACE_IN:
- if((ifp->trace & IF_TRACE_NOBC)
- && (Tracef[type].addrtest != NULLFP)
- && (*Tracef[type].addrtest)(ifp,bp) == 0)
- return; /* broadcasts are suppressed */
- #ifdef MONITOR
- if ((ifp->trace & IF_TRACE_PLAIN) == IF_TRACE_PLAIN)
- fprintf(ifp->trfp, "(%s) ", kissname(ifp, bp, type));
- else
- #endif
- fprintf(ifp->trfp,"\n%s - %s recv:\n",cp,ifp->name);
- break;
- case IF_TRACE_OUT:
- #ifdef MONITOR
- if ((ifp->trace & IF_TRACE_PLAIN) == IF_TRACE_PLAIN)
- fprintf(ifp->trfp, "(%s) ", kissname(ifp, bp, type));
- else
- #endif
- fprintf(ifp->trfp,"\n%s - %s sent:\n",cp,ifp->name);
- break;
- }
- if(bp == NULLBUF || (size = len_p(bp)) == 0){
- fprintf(ifp->trfp,"empty packet!!\n");
- return;
- }
-
- if(type < NCLASS)
- func = Tracef[type].tracef;
- else
- func = NULLVFP;
-
- dup_p(&tbp,bp,0,size);
- if(tbp == NULLBUF){
- fprintf(ifp->trfp,nospace);
- return;
- }
- #ifdef MONITOR
- Trace_compact_header = ((ifp->trace&IF_TRACE_PLAIN) == IF_TRACE_PLAIN);
- #endif
- if(func != NULLVFP)
- (*func)(ifp->trfp,&tbp,1);
- #ifdef MONITOR
- if ((ifp->trace & IF_TRACE_PLAIN) == IF_TRACE_PLAIN)
- plain_dump(ifp->trfp, &tbp);
- else
- #endif
- if(ifp->trace & IF_TRACE_ASCII){
- /* Dump only data portion of packet in ascii */
- ascii_dump(ifp->trfp,&tbp);
- } else if(ifp->trace & IF_TRACE_HEX){
- /* Dump entire packet in hex/ascii */
- free_p(tbp);
- dup_p(&tbp,bp,0,len_p(bp));
- if(tbp != NULLBUF)
- hex_dump(ifp->trfp,&tbp);
- else
- fprintf(ifp->trfp,nospace);
- }
- free_p(tbp);
- }
-
- /* Dump packet bytes, no interpretation */
- void
- raw_dump(ifp,direction,bp)
- struct iface *ifp;
- int direction;
- struct mbuf *bp;
- {
- struct mbuf *tbp;
-
- /* Dump entire packet in hex/ascii */
- fprintf(ifp->trfp,"\n******* raw packet dump (%s %s)\n",
- ((direction & IF_TRACE_OUT) ? "send" : "recv"),ifp->name);
- dup_p(&tbp,bp,0,len_p(bp));
- if(tbp != NULLBUF)
- hex_dump(ifp->trfp,&tbp);
- else
- fprintf(ifp->trfp,nospace);
- fprintf(ifp->trfp,"*******\n");
- free_p(tbp);
- return;
- }
-
- /* Dump an mbuf in hex */
- static void
- hex_dump(fp,bpp)
- FILE *fp;
- register struct mbuf **bpp;
- {
- int16 n;
- int16 address;
- char buf[16];
-
- if(bpp == NULLBUFP || *bpp == NULLBUF)
- return;
-
- address = 0;
- pullup(bpp, buf, 1); /* remove first zero byte */
- while((n = pullup(bpp,buf,sizeof(buf))) != 0){
- fmtline(fp,address,buf,n);
- address += n;
- }
- }
- /* Dump an mbuf in ascii */
- static void
- ascii_dump(fp,bpp)
- FILE *fp;
- register struct mbuf **bpp;
- {
- int c;
- register int16 tot;
-
- if(bpp == NULLBUFP || *bpp == NULLBUF)
- return;
-
- tot = 0;
- while((c = PULLCHAR(bpp)) != -1){
- if((tot % 64) == 0)
- fprintf(fp,"%04x ",tot);
- #ifdef TNOS_68K
- fprintf (fp, "%c", isprint(uchar(c)) ? c : '.');
- #else
- putc(isprint(uchar(c)) ? c : '.',fp);
- #endif
- if((++tot % 64) == 0)
- fprintf(fp,"\n");
- }
- if((tot % 64) != 0)
- fprintf(fp,"\n");
- }
- /* Print a buffer up to 16 bytes long in formatted hex with ascii
- * translation, e.g.,
- * 0000: 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 0123456789:;<=>?
- */
- static void
- fmtline(fp,addr,buf,len)
- FILE *fp;
- int16 addr;
- char *buf;
- int16 len;
- {
- char line[80];
- register char *aptr,*cptr;
- register char c;
-
- memset(line,' ',sizeof(line));
- ctohex(line,(int16)hibyte(addr));
- ctohex(line+2,(int16)lobyte(addr));
- aptr = &line[6];
- cptr = &line[55];
- while(len-- != 0){
- c = *buf++;
- ctohex(aptr,(int16)uchar(c));
- aptr += 3;
- c &= 0x7f;
- *cptr++ = isprint(uchar(c)) ? c : '.';
- }
- *cptr++ = '\n';
- #ifdef TNOS_68K
- *cptr = 0;
- fprintf (fp, line);
- #else
- fwrite(line,1,(unsigned)(cptr-line),fp);
- #endif
- }
- /* Convert byte to two ascii-hex characters */
- static void
- ctohex(buf,c)
- register char *buf;
- register int16 c;
- {
- static char hex[] = "0123456789abcdef";
-
- *buf++ = hex[hinibble(c)];
- *buf = hex[lonibble(c)];
- }
-
- #ifdef MONITOR
- /* Dump an mbuf in ascii with newlines but no others. */
- /* Actually, we do limited VT100 parsing, since that seems popular here */
- static void
- plain_dump(fp,bpp)
- FILE *fp;
- register struct mbuf **bpp;
- {
- struct mbuf *tmp;
- int c, esc, nl;
-
- if (bpp == NULLBUFP || *bpp == NULLBUF)
- return;
-
- /* check for lots of non-ASCII, non-VT100 and ascii_dump instead? */
- dup_p(&tmp, *bpp, 0, len_p(*bpp));
- nl = 0;
- while ((c = PULLCHAR(&tmp)) != -1)
- {
- /*
- * Printable characters are okay, as are \n \t \r \b \f \a \E
- * Nulls and other control characters are verboten, as are meta
- * controls. Meta-printables are accepted, since they may be
- * intended as PC graphics (but don't expect them to dump right
- * from here because I don't decode them. Maybe someday).
- */
- if (c < 8 || (c > 13 && c < 26) || (c > 27 && c < 32) ||
- (c > 126 && c < 174) || c > 223)
- nl = 1;
- }
- if (nl)
- {
- ascii_dump(fp, bpp);
- return;
- }
- esc = 0;
- nl = 1;
- while ((c = PULLCHAR(bpp)) != -1)
- {
- if (c == 0x1B)
- esc = !esc;
- else if (esc == 1 && c == '[')
- esc = 2;
- else if (esc == 1)
- esc = 0;
- else if (esc == 2 && c != ';' && !isdigit(c))
- {
- /* handle some common cases? */
- esc = 0;
- }
- else if (esc == 0 && c == '\r')
- {
- fprintf(fp, "\n");
- nl = 1;
- }
- /* safe programming: not everyone *always* agrees on isprint */
- else if (esc == 0 && c != '\n' && (isprint(c) || c == '\t'))
- {
- fprintf(fp, "%c", c);
- nl = 0;
- }
- }
- if (!nl)
- fprintf(fp, "\n");
- }
- #endif
-
-
- /* Modify or displace interface trace flags */
- int
- dotrace(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- struct iface *ifp;
- struct tracecmd *tp;
-
- if(argc < 2){
- for(ifp = Ifaces; ifp != NULLIF; ifp = ifp->next)
- showtrace(ifp);
- return 0;
- }
- if((ifp = if_lookup(argv[1])) == NULLIF){
- tprintf(Badinterface,argv[1]);
- return 1;
- }
- if(ifp->port){
- tprintf("No trace on this interface - use master.\n");
- return 1;
- }
- if(argc == 2){
- showtrace(ifp);
- return 0;
- }
- /* MODIFY THIS TO HANDLE MULTIPLE OPTIONS */
- if(argc >= 3){
- for(tp = Tracecmd;tp->name != NULLCHAR;tp++)
- if(strncmp(tp->name,argv[2],strlen(argv[2])) == 0)
- break;
- if(tp->name != NULLCHAR)
- ifp->trace = (ifp->trace & ~tp->mask) | tp->val;
- else
- ifp->trace = htoi(argv[2]);
- }
- /* Always default to stdout unless trace file is given */
- if(ifp->trfp != NULLFILE && ifp->trfp != stdout)
- fclose(ifp->trfp);
- ifp->trfp = stdout;
- if(ifp->trfile != NULLCHAR)
- free(ifp->trfile);
- ifp->trfile = NULLCHAR;
-
- if(argc >= 4){
- if((ifp->trfp = fopen(argv[3],APPEND_TEXT)) == NULLFILE){
- tprintf("Can't write to %s\n",argv[3]);
- ifp->trfp = stdout;
- } else {
- ifp->trfile = strdup(argv[3]);
- }
- }
- showtrace(ifp);
- return 0;
- }
- /* Display the trace flags for a particular interface */
- static void
- showtrace(ifp)
- register struct iface *ifp;
- {
- if(ifp == NULLIF)
- return;
- tprintf("%s:",ifp->name);
- if(ifp->port){
- tprintf(" trace on master interface only.\n");
- return;
- }
- if(ifp->trace & (IF_TRACE_IN | IF_TRACE_OUT | IF_TRACE_RAW)){
- if(ifp->trace & IF_TRACE_IN)
- tprintf(" input");
- if(ifp->trace & IF_TRACE_OUT)
- tprintf(" output");
-
- if(ifp->trace & IF_TRACE_NOBC)
- tprintf(" - no broadcasts");
-
- #ifdef MONITOR
- if ((ifp->trace & IF_TRACE_PLAIN) == IF_TRACE_PLAIN)
- tprintf(" (Monitoring)");
- else
- #endif
- if(ifp->trace & IF_TRACE_HEX)
- tprintf(" (Hex/ASCII dump)");
- else if(ifp->trace & IF_TRACE_ASCII)
- tprintf(" (ASCII dump)");
- else
- tprintf(" (headers only)");
-
- if(ifp->trace & IF_TRACE_RAW)
- tprintf(" Raw output");
-
- if(ifp->trfile != NULLCHAR)
- tprintf(" trace file: %s",ifp->trfile);
- tprintf("\n");
- } else
- tprintf(" tracing off\n");
- }
-
- /* shut down all trace files */
- void
- shuttrace()
- {
- struct iface *ifp;
-
- for(ifp = Ifaces; ifp != NULLIF; ifp = ifp->next){
- if(ifp->trfp != NULLFILE && ifp->trfp != stdout)
- fclose(ifp->trfp);
- if(ifp->trfile != NULLCHAR)
- free(ifp->trfile);
- ifp->trfile = NULLCHAR;
- ifp->trfp = NULLFILE;
- }
- }
-
- #ifdef PPP
- /* Log messages of the form
- * Tue Jan 31 00:00:00 1987 44.64.0.7:1003 open FTP
- */
- #if defined(ANSIPROTO)
- void
- trace_log(struct iface *ifp,char *fmt, ...)
- {
- va_list ap;
- char *cp;
- long t;
-
- if(ifp->trfp == NULLFILE)
- return;
-
- time(&t);
- cp = ctime(&t);
- rip(cp);
- fprintf(ifp->trfp,"%s",cp);
-
- fprintf(ifp->trfp," - ");
- va_start(ap,fmt);
- vfprintf(ifp->trfp,fmt,ap);
- va_end(ap);
- fprintf(ifp->trfp,"\n");
- }
- #else
- /*VARARGS2*/
- void
- trace_log(ifp,fmt,arg1,arg2,arg3,arg4,arg5)
- struct iface *ifp;
- char *fmt;
- int arg1,arg2,arg3,arg4,arg5;
- {
- char *cp;
- long t;
-
- if(ifp->trfp == NULLFILE)
- return;
-
- time(&t);
- cp = ctime(&t);
- rip(cp);
- fprintf(ifp->trfp,"%s",cp);
-
- fprintf(ifp->trfp," - ");
- fprintf(ifp->trfp,fmt,arg1,arg2,arg3,arg4,arg5);
- fprintf(ifp->trfp,"\n");
- }
- #endif
- #endif /* PPP */
-
- #endif /*TRACE*/
-
-